
package com.saas.ability.core.base.util;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 */
public class BeanToMapUtil {
    private static final Logger logger = LoggerFactory.getLogger(BeanToMapUtil.class);

    /**
     * 将一个 Map 对象转化为一个 JavaBean
     *
     * @param type 要转化的类型
     * @param map  包含属性值的 map
     * @return 转化出来的 JavaBean 对象
     * @throws IntrospectionException    如果分析类属性失败
     * @throws IllegalAccessException    如果实例化 JavaBean 失败
     * @throws InstantiationException    如果实例化 JavaBean 失败
     * @throws InvocationTargetException 如果调用属性的 setter 方法失败
     */
    public static Object convertMap(Class type, Map map)
            throws IntrospectionException, IllegalAccessException,
            InstantiationException, InvocationTargetException {
        BeanInfo beanInfo = Introspector.getBeanInfo(type); // 获取类属性
        Object obj = type.newInstance(); // 创建 JavaBean 对象

        // 给 JavaBean 对象的属性赋值
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (int i = 0; i < propertyDescriptors.length; i++) {
            PropertyDescriptor descriptor = propertyDescriptors[i];
            String propertyName = descriptor.getName();

            if (map.containsKey(propertyName)) {
                // 下面一句可以 try 起来，这样当一个属性赋值失败的时候就不会影响其他属性赋值。
                try {
                    Object value = map.get(propertyName);

                    Object[] args = new Object[1];
                    args[0] = value;
                    descriptor.getWriteMethod().invoke(obj, args);
                }catch (Exception e){
                   //throw new ConversionException(e);
                    logger.error("转换" + propertyName + "属性出错!{}",e.getMessage());
                    e.printStackTrace();
                }
            }
        }
        return obj;
    }

    /**
     * 将一个 JavaBean 对象转化为一个  Map
     *
     * @param bean 要转化的JavaBean 对象
     * @return 转化出来的  Map 对象
     * @throws IntrospectionException    如果分析类属性失败
     * @throws IllegalAccessException    如果实例化 JavaBean 失败
     * @throws InvocationTargetException 如果调用属性的 setter 方法失败
     */
    public static Map convertBean(Object bean)
            throws IntrospectionException, IllegalAccessException, InvocationTargetException {
        Class type = bean.getClass();
        Map returnMap = new HashMap();
        BeanInfo beanInfo = Introspector.getBeanInfo(type);

        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (int i = 0; i < propertyDescriptors.length; i++) {
            PropertyDescriptor descriptor = propertyDescriptors[i];
            String propertyName = descriptor.getName();
            if (!propertyName.equals("class")) {
                Method readMethod = descriptor.getReadMethod();
                Object result = readMethod.invoke(bean, new Object[0]);
                if (result != null) {
                    returnMap.put(propertyName, result);
                } else {
                    returnMap.put(propertyName, "");
                }
            }
        }
        return returnMap;
    }

    /**
     * 采用BeanUtils工具把map转换成javabean
     * 因为BeanUtils不提供直接将字符串转换成Date（java.util.Date）
     * @param map
     * @param type
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static Object transMap2Bean(Map<String, Object> map, Class type) throws Exception{
        if (map == null)
            return null;

        //源码里有提供 DateLocaleConverter 这个类做注册的转化器
        //ConvertUtils.register(new DateLocaleConverter(), Date.class);
        // 这里一定要注册默认值，使用null也可以
       // ConvertUtils.register(new BigDecimalLocaleConverter(), BigDecimal.class);
        ConvertUtils.register(new Converter() {
            @Override
            public Object convert(Class type, Object value) {
                if (value == null) {
                    return null;
                }
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String str = "";
                if(value instanceof Long){
                    str = String.valueOf(value);
                }
                if(value instanceof Integer){
                    str = String.valueOf(value);
                }
                if(value instanceof String){
                    str = (String)value;
                }
                if (str.trim().equals("")) {
                    return null;
                }
                //return DateUtils.parseDate(str);
                try {
                    return sdf.parse(str);
                } catch (ParseException e) {
                    sdf = new SimpleDateFormat("yyyy-MM-dd");
                    try {
                        return sdf.parse(str);
                    }catch (ParseException e1){
                        try {
                            Long time = new Long(str);
                            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                            String timeString = sdf.format(time);
                            return sdf.parse(timeString);
                        } catch (ParseException e2) {
                           throw new RuntimeException("转换日期出错!"+str);
                        }
                    }
                }
            }
        }, Date.class);
        Object obj;
        try {
            obj = type.newInstance(); // 创建 JavaBean 对象
            BeanUtils.populate(obj, map);
        } catch (Exception e) {
            throw new Exception("Map<String,Object>转化Bean异常");
        }
        return obj;
    }

    /**
     * 采用BeanUtils工具将一个 JavaBean 对象转化为一个  Map
     * @param obj
     * @return
     */
    public static Map<?, ?> objectToMap(Object obj) {
        if(obj == null)
            return null;
        return new org.apache.commons.beanutils.BeanMap(obj);
    }




}